﻿#ifndef QMYSQL_H
#define QMYSQL_H
#include<QString>
#include<QSqlDatabase>
#include<QSqlQuery>
#include<QStack>
#include<QSqlDriver>
#include<QScopedPointer>
class XQLog;
#define XQMysqlInfo XQLog("XQMysqlInfo")
//mysql数据库
class XQMySql:public QObject
{
	Q_OBJECT
public:
	XQMySql(QObject* parent=nullptr);
	XQMySql(QString SqlName,QString host, quint16 port, QString name, QString password, QString DataBase, QObject* parent = nullptr);
	XQMySql(QString host,quint16 port,QString name ,QString password,QString DataBase, QObject* parent = nullptr);
	~XQMySql();
	//获取全局区的mysql数据库
	static XQMySql*globalInstance();
	//新的连接覆盖并获取
	static XQMySql* globalInstance(QString host, quint16 port, QString name, QString password, QString DataBase);
public:
	//拷贝数据库
	XQMySql* cloneDatabase( const QString& connectionName = QString());
	//拷贝数据库返回智能指针
	QScopedPointer<XQMySql> cloneDatabase_ScopedPointer(const QString& connectionName=QString());
	//获取连接状态成功或者失败
	bool isOpen()const;
	//获取QSqlQuery
	QSqlQuery SqlQuery()const;
	//获取QSqlDatabase数据库
	QSqlDatabase database()const;
	//获取错误信息
	QString error()const;
	//获取连接失败重连次数
	int reconnectionCount()const;
	//获取延迟时间
	int sleepTime()const;
public:
	//连接MySql数据库
	void connection(QString SqlName, QString host, quint16 port, QString name, QString password, QString DataBase);
	//添加服务器的主机地址和端口
	void addHostPort(QString host, quint16 port);
	//删除一个主机
	void removeHostPort(QString host);
	//设置连接失败重连次数
	void setReconnectionCount(int count);
	//设置延迟时间
	void setSleepTime(int sleep);
public:
	//执行sql命令
	bool Query(const QString& query);
	//已QString("%1 %2").arg(1).arg(2)形式初始化sql后执行
	template <typename ...Args>
	bool Query(const QString& query, Args&& ...args);
public:
	//获取32位uuid
	QString uuid(const QString& variate=QString());
	//获取服务器当前时间
	QDateTime ctime(const QString& variate = QString());
public:
	//获取结果
	bool result();//只判断是否有结果
	//只获取指定列的数据
	bool result(QVariant& ret,int nSel=0);
	//获取一行
	bool result(QVariantList& ret);
	//获取一列进栈
	bool result(QStack<QVariant>& ret);
	//获取返回的所有数据转QString
	QList<QStringList> result_all_toString();
	//获取返回的所有数据
	QList<QVariantList> result_all();
	//获取一列全部数据转QString
	QStringList  result_oneColumn_toString(int nSel = 0);
	//获取一列全部数据
	QVariantList result_oneColumn(int nSel = 0);
	//获取第一行全部数据转QString
	QStringList  result_oneRow_toString();
	//获取第一行全部数据
	QVariantList result_oneRow();
	//获取一个数据转QString
	QString result_one_toString();
	//获取一个数据
	QVariant result_one();
public:
	//查询指定表名是否存在
	bool tabelExists(const QString& tableName);
	//查询表内的行数
	qint64 SELECT_COUNT(const QString& tableName, const QString& Where = QString());
	template <typename ...Args>
	qint64 SELECT_COUNT(const QString& tableName, const QString& Where, Args&& ...args);//Where QString构造方式
	//查询数据
	bool SELECT(const QString& tableName, const QStringList& fields, const QString& condition = QString());
	template <typename ...Args>
	bool SELECT(const QString& tableName, const QStringList& fields, const QString& condition, Args&& ...args);
	bool SELECT_Where(const QString& tableName, const QStringList& fields, const QString& Where);
	template <typename ...Args>
	bool SELECT_Where(const QString& tableName, const QStringList& fields, const QString& Where, Args&& ...args);
	//查询表的所有字段
	QStringList fieldList(const QString& tableName);
	//查询指定字段的所有数据
	QVariantList findData(const QString& tableName, const QString& field);
	//查询指定字段的所有数据转QString
	QStringList findData_toString(const QString& tableName, const QString& field);
	//查询指定字段合集的所有数据
	QList<QVariantList> findDatas(const QString& tableName, const QStringList& fields);
	//查询指定字段合集的所有数据转QString
	QList<QStringList> findDatas_toString(const QString& tableName, const QStringList& fields);
	//查询表所有数据
	QList<QVariantList> findDataAll(const QString& tableName);
	//查询表所有数据转QString
	QList<QStringList> findDataAll_toString(const QString& tableName);
public:
	//插入数据
	bool INSERT(const QString& tableName, const QStringList& fields,QVariantList&& datas);
	bool INSERTS(const QString& tableName, const QStringList& fields,const QList<QVariantList>& datas);
	template <typename ...Args>
	bool INSERT(const QString& tableName,const QStringList& fields, Args&& ...args);
public:
	//更新数据
	bool UPDATE(const QString& tableName, const QString& Where, const QStringList& fields,QVariantList&& datas);
	template <typename ...Args>
	bool UPDATE(const QString& tableName, const QString& Where, const QStringList& fields, Args&& ...args);
public:
	//删除数据
	//删除一条数据,已相等做判断(1字段1数据，自动链接做&&判断)
	template <typename ...Args>
	void deleteTableData(const QString& tableName,size_t maxNum, Args&& ...args);
signals:
	//命令错误发生
	void sqlError(const QString& error);
	//连接mysql成功
	void connectionSucceed();
protected:
	void init();
	//打开数据库 重连次数 延迟时间秒
	bool openDatabase(QSqlDatabase& database,int count=0,int sleep=5);
private:
	static XQMySql* m_mysql;//全局默认mysql
	static XQLog* m_log;//mysql全局日志
	QMap<QString,quint16> m_hostPort;//主机和端口列表
	QString m_SqlName;
	QSqlQuery m_sqlQuery;
	int m_reconnectionCount = 0;//重连次数
	int m_sleepTime = 5;//延迟时间
};
//格式转化递归
template <typename _Ty, typename ...Args>
void format(const QStringList& ret,int nSel, _Ty&& data, Args&& ...args);
//插入表数据
void _insertStringList(QStringList& list, const char* data);
void _insertStringList(QStringList& list, const QString data);
template<typename _Ty>
inline void _insertStringList(QStringList& list, _Ty  data)
{
	list << QString("%1").arg(data);
}
template <typename _Ty, typename ...Args>
inline void _insertStringList(QStringList& list,_Ty data, Args&& ...args)
{
	_insertStringList(list, data);
	_insertStringList(list, std::forward<Args>(args)...);
}
template<typename ...Args>
inline qint64 XQMySql::SELECT_COUNT(const QString& tableName, const QString& Where, Args && ...args)
{
	QString str= Where;
	QStringArgs(str, std::forward<Args>(args)...);
	return SELECT_COUNT(tableName,str);
}
template<typename ...Args>
inline bool XQMySql::SELECT(const QString& tableName, const QStringList& fields, const QString& condition, Args && ...args)
{
	QString str=condition;
	QStringArgs(str, std::forward<Args>(args)...);
	return SELECT(tableName, fields, str);
}
template<typename ...Args>
inline bool XQMySql::SELECT_Where(const QString& tableName, const QStringList& fields, const QString& Where, Args && ...args)
{
	QString str=Where;
	QStringArgs(str, std::forward<Args>(args)...);
	return SELECT_Where(tableName, fields, str);
}
template<typename ...Args>
inline bool XQMySql::INSERT(const QString& tableName, const QStringList& fields, Args && ...args)
{
	QVariantList VariantList = { std::forward<Args>(args)... };
	return INSERT(tableName, VariantList,fields);
}
template<typename ...Args>
inline bool XQMySql::UPDATE(const QString& tableName, const QString& Where, const QStringList& fields, Args && ...args)
{
	QVariantList VariantList = { std::forward<Args>(args)... };
	return UPDATE(tableName,Where, VariantList,fields);
}

//插入全部表数据
void _insertStringListAll(QStringList& list, const char* data);
void _insertStringListAll(QStringList& list, const QString data);
template<typename _Ty>
inline void _insertStringListAll(QStringList& list, _Ty  data)
{
	list << QString("%1").arg(data);
}
template <typename _Ty, typename ...Args>
inline void _insertStringListAll(QStringList& list, _Ty data, Args&& ...args)
{
	_insertStringListAll(list, data);
	_insertStringListAll(list, std::forward<Args>(args)...);
}
//删除表数据
template<typename ...Args>
inline void XQMySql::deleteTableData(const QString& tableName, size_t maxNum, Args&& ...args)
{
	QStringList list;
	_insertStringList(list, std::forward<Args>(args)...);
	QString value;
	size_t count = 0;//数量
	for (auto& v : list)
	{
		if (count % 2 == 0)//字段
		{
			value += QString("`%1`=").arg(v);
		}
		else
		{
			value += QString("%1 and").arg(v);
		}
		count++;
	}
	if (!value.isEmpty())
		value.remove(value.size() - 3, 3);
	QString sql = QString("delete from `%1` where %2 ").arg(tableName).arg(value);
	if (maxNum != 0)
		sql += QString("LIMIT %1").arg(maxNum);
	/*qDebug() << value;
	qDebug() << sql;*/
	Query(sql);
}

//SQL语句组合
template <typename _Ty>
inline void QStringArgs(QString& str, _Ty&& data)
{
	str = str.arg(data);
}
template <typename _Ty, typename ...Args>
inline void QStringArgs(QString& str, _Ty&& data, Args&& ...args)
{
	str = str.arg(data);
	QStringArgs(str, std::forward<Args>(args)...);
}
template<typename ...Args>
inline bool XQMySql::Query(const QString& query, Args&& ...args)
{
	QString str = query;
	QStringArgs(str, std::forward<Args>(args)...);
	//qInfo() << str;
	return Query(str);
}
#endif

template<typename _Ty, typename ...Args>
inline void format(const QStringList& ret, int nSel, _Ty&& data, Args && ...args)
{
	format(ret[nSel], data);//格式转化
	format(ret,nSel+1, std::forward<Args>(args)...);//递归解包
}
